package cn.summit.log;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import cn.summit.log.config.AspectLogProperties;
import cn.summit.log.dto.LogInfoDTO;
import cn.summit.log.service.AccessLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;


@Slf4j
@Aspect
public class AccessLogAspect {

	private final AccessLogService accessLogService;

	private final AspectLogProperties aspectLogProperties;


	public AccessLogAspect(AccessLogService accessLogService,
			AspectLogProperties aspectLogProperties) {
		this.accessLogService = accessLogService;
		this.aspectLogProperties = aspectLogProperties;

	}

	/**
	 * 切入点
	 */
	@Pointcut(value = "execution(public * cn..*.controller..*Controller.*(..))")
	public void logPointcut() {
	}

	/**
	 * 环绕通知
	 *
	 * @param joinPoint 信息
	 * @return obj
	 * @throws Throwable 异常
	 */
	@Around("logPointcut()")
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
		LogInfoDTO logInfoDTO = doProceedBefore(joinPoint);
		if (logInfoDTO == null) {
			return joinPoint.proceed();
		}
		log.debug(aspectLogProperties.getName() + "日志开始打印");
		accessLogService.doBefore(logInfoDTO);

		String uuid = UUID.randomUUID().toString();

		if (aspectLogProperties.getArgsDetailLog()) {
			System.out.println("===========================================");
			ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
					.getRequestAttributes();
			if (attributes == null) {
				log.error("请求request获取失败");
				return joinPoint.proceed();
			}
			HttpServletRequest request = attributes.getRequest();

			log.debug("requestInfo=>标识[{}] IP:{} ARGS:{}", uuid, request.getRemoteAddr(),
					Arrays.toString(joinPoint.getArgs()));

		}
		//执行方法
		Object result = joinPoint.proceed();

		if (aspectLogProperties.getArgsDetailLog()) {
			log.debug("responseInfo=>标识[{}]RESPONSE:{}", uuid, result);
		}

		doProceedAfter(joinPoint, logInfoDTO);
		accessLogService.doAfter(logInfoDTO);

		return result;
	}

	/**
	 * 环绕后处理
	 *
	 * @param joinPoint 信息
	 * @param logInfoDTO 访问信息
	 */
	private void doProceedAfter(ProceedingJoinPoint joinPoint, LogInfoDTO logInfoDTO) {
		logInfoDTO.setEndTime(LocalDateTime.now());
	}

	/**
	 * 环绕前处理
	 *
	 * @param joinPoint 信息
	 * @return 访问信息
	 */
	private LogInfoDTO doProceedBefore(ProceedingJoinPoint joinPoint) {
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
				.getRequestAttributes();
		if (requestAttributes == null) {
			log.error("获取ServletRequestAttributes failed");
			return null;
		}
		Method method = signature.getMethod();
		Class<?> controllerClass = method.getDeclaringClass();

		LogInfoDTO logInfo = new LogInfoDTO();
		HttpServletRequest request = requestAttributes.getRequest();
		logInfo.setRequest(request);
		logInfo.setHttpMethod(request.getMethod());
		logInfo.setUri(request.getRequestURI());
		logInfo.setClassMethod(controllerClass.getName() + "#" + method.getName());
		//logInfo.setMethodDescription();
		logInfo.setStartTime(LocalDateTime.now());
		//logInfo.setErrorInfo();
		return logInfo;
	}
}
